package hn.sigit.interop.gmlproducers;

import hn.sigit.dao.hnd.ladmshadow.ParcelDAO;
import hn.sigit.model.commons.IParcel;
import hn.sigit.model.commons.ITransaction;
import hn.sigit.model.commons.ISpatialZone;
import hn.sigit.model.hnd.administrative.HND_SpatialZoneInTransaction;
import hn.sigit.model.hnd.administrative.HND_Transaction;

import java.util.ArrayList;
import java.util.List;

import org.deegree.commons.tom.TypedObjectNode;
import org.deegree.commons.tom.genericxml.GenericXMLElementContent;
import org.deegree.commons.tom.primitive.PrimitiveType;
import org.deegree.feature.GenericFeature;
import org.deegree.feature.property.GenericProperty;
import org.deegree.feature.property.Property;
import org.deegree.feature.property.SimpleProperty;
import org.deegree.feature.types.GenericFeatureType;
import org.deegree.feature.types.property.ArrayPropertyType;
import org.deegree.feature.types.property.PropertyType;
import org.deegree.feature.types.property.SimplePropertyType;
import org.deegree.gml.GMLVersion;

public class TransactionGMLProducer extends GMLProducer<ITransaction> {
	private static final SimplePropertyType jurisdictionCodePropertyType = new SimplePropertyType(newQName("jurisdictionCode"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType presentationIdPropertyType = new SimplePropertyType(newQName("presentationId"), 1, 1, PrimitiveType.INTEGER, false, false, null);
	private static final SimplePropertyType presentationDatePropertyType = new SimplePropertyType(newQName("presentationDate"), 1, 1, PrimitiveType.DATE_TIME, false, false, null);
	private static final SimplePropertyType presenterIdentityPropertyType = new SimplePropertyType(newQName("presenterIdentity"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType presenterNamePropertyType = new SimplePropertyType(newQName("presenterName"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType descriptionPropertyType = new SimplePropertyType(newQName("description"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType transactionTypePropertyType = new SimplePropertyType(newQName("transactionType"), 1, 1, PrimitiveType.STRING, false, false, null);
	//private static final SimplePropertyType transactionSubTypePropertyType = new SimplePropertyType(newQName("transactionSubType"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType analysisDictumPropertyType = new SimplePropertyType(newQName("analysisDictum"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType additionalObservationsPropertyType = new SimplePropertyType(newQName("additionalObservations"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType currentActivityPropertyType = new SimplePropertyType(newQName("currentActivity"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType receptionistUserNamePropertyType = new SimplePropertyType(newQName("receptionistUserName"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType receptionistFullNamePropertyType = new SimplePropertyType(newQName("receptionistFullName"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType approverUserNamePropertyType = new SimplePropertyType(newQName("approverUserName"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType approverFullNamePropertyType = new SimplePropertyType(newQName("approverFullName"), 1, 1, PrimitiveType.STRING, false, false, null);
	private static final SimplePropertyType localApprovalDatePropertyType = new SimplePropertyType(newQName("localApprovalDate"), 0, 1, PrimitiveType.DATE_TIME, false, true, null);
	private static final ArrayPropertyType parcelsBeforeTransactionPropertyType = new ArrayPropertyType(newQName("parcelsBeforeTransaction"), 1, 1, false, false, null);
	private static final ArrayPropertyType parcelsAfterTransactionPropertyType = new ArrayPropertyType(newQName("parcelsAfterTransaction"), 1, 1, false, false, null);
	
	private static GenericFeatureType transactionFeatureType;
	
	static {
		transactionFeatureType = buildFeatureType();
	}
	
	private static GenericFeatureType buildFeatureType() {
		List<PropertyType> propertyTypeList = new ArrayList<PropertyType>();
		propertyTypeList.add(jurisdictionCodePropertyType);
		propertyTypeList.add(presentationIdPropertyType);
		propertyTypeList.add(presentationDatePropertyType);
		propertyTypeList.add(presenterIdentityPropertyType);
		propertyTypeList.add(presenterNamePropertyType);
		propertyTypeList.add(descriptionPropertyType);
		propertyTypeList.add(transactionTypePropertyType);
		//propertyTypeList.add(transactionSubTypePropertyType);
		propertyTypeList.add(analysisDictumPropertyType);
		propertyTypeList.add(additionalObservationsPropertyType);
		propertyTypeList.add(currentActivityPropertyType);
		propertyTypeList.add(receptionistUserNamePropertyType);
		propertyTypeList.add(receptionistFullNamePropertyType);
		propertyTypeList.add(approverUserNamePropertyType);
		propertyTypeList.add(approverFullNamePropertyType);
		propertyTypeList.add(localApprovalDatePropertyType);
		propertyTypeList.add(parcelsBeforeTransactionPropertyType);
		propertyTypeList.add(parcelsAfterTransactionPropertyType);
		
		return new GenericFeatureType(newQName("Transaction"), propertyTypeList, false);
	}
	
	public TransactionGMLProducer(String jurisdictionCode, ITransaction transaction) {
		super(jurisdictionCode, transaction);
	}
	
	@Override
	public GenericFeature buildFeature() {
		ITransaction trx = getObjectFeature();
		List<Property> propertyList = new ArrayList<Property>();

		SimpleProperty jurisdictionCode = new SimpleProperty(jurisdictionCodePropertyType,
				getJurisdictionCode(),
				PrimitiveType.STRING);
		propertyList.add(jurisdictionCode);

		SimpleProperty presentationId = new SimpleProperty(presentationIdPropertyType,
				trx.getPresentationId().toString(),
				PrimitiveType.INTEGER);
		propertyList.add(presentationId);
		
		SimpleProperty presentationDate = new SimpleProperty(presentationDatePropertyType,
				xsDateTime(trx.getPresentationDate()),
				PrimitiveType.DATE_TIME);
		propertyList.add(presentationDate);

		SimpleProperty presenterIdentity = new SimpleProperty(presenterIdentityPropertyType,
				trx.getExtParty() != null ? nvl(trx.getExtParty().getFormalIdentity()) : "",
				PrimitiveType.STRING);
		propertyList.add(presenterIdentity);
		
		SimpleProperty presenterName = new SimpleProperty(presenterNamePropertyType,
				trx.getExtParty() != null ? nvl(trx.getExtParty().getName()) : "",
				PrimitiveType.STRING);
		propertyList.add(presenterName);

		SimpleProperty description = new SimpleProperty(descriptionPropertyType,
				nvl(trx.getDescription()),
				PrimitiveType.STRING);
		propertyList.add(description);

		SimpleProperty transactionType = new SimpleProperty(transactionTypePropertyType,
				trx.getRequestType() != null ? nvl(trx.getRequestType().name()) : "",
				PrimitiveType.STRING);
		propertyList.add(transactionType);
		
		/*
		SimpleProperty transactionSubType = new SimpleProperty(transactionSubTypePropertyType,
				trx.getRequestSubType() != null ? nvl(trx.getRequestSubType().name()) : "",
				PrimitiveType.STRING);
		propertyList.add(transactionSubType);
		*/
		
		SimpleProperty analysisDictum = new SimpleProperty(analysisDictumPropertyType,
				nvl(trx.getAnalysisDictum()),
				PrimitiveType.STRING);
		propertyList.add(analysisDictum);
		
		SimpleProperty additionalObservations = new SimpleProperty(additionalObservationsPropertyType,
				nvl(trx.getAdditionalObservations()),
				PrimitiveType.STRING);
		propertyList.add(additionalObservations);

		SimpleProperty currentActivity = new SimpleProperty(currentActivityPropertyType,
				nvl(trx.getCurrentActivity().toString()),
				PrimitiveType.STRING);
		propertyList.add(currentActivity);

		SimpleProperty receptionistUserName = new SimpleProperty(receptionistUserNamePropertyType,
				nvl(trx.getReceptionistUserName()),
				PrimitiveType.STRING);
		propertyList.add(receptionistUserName);

		SimpleProperty receptionistFullName = new SimpleProperty(receptionistFullNamePropertyType,
				nvl(trx.getReceptionistFullName()),
				PrimitiveType.STRING);
		propertyList.add(receptionistFullName);

		SimpleProperty approverUserName = new SimpleProperty(approverUserNamePropertyType,
				nvl(trx.getApproverUserName()),
				PrimitiveType.STRING);
		propertyList.add(approverUserName);

		SimpleProperty approverFullName = new SimpleProperty(approverFullNamePropertyType,
				nvl(trx.getApproverFullName()),
				PrimitiveType.STRING);
		propertyList.add(approverFullName);

		if (trx.getCompletionDate() != null) {
			SimpleProperty completionDate = new SimpleProperty(localApprovalDatePropertyType,
					xsDateTime(trx.getCompletionDate()),
					PrimitiveType.DATE_TIME);
			propertyList.add(completionDate);
		}
		
		GenericProperty parcelsBeforeTransaction = generateParcelsProperty(parcelsBeforeTransactionPropertyType, true);
		propertyList.add(parcelsBeforeTransaction);
		
		GenericProperty parcelsAfterTransaction = generateParcelsProperty(parcelsAfterTransactionPropertyType, false);
		propertyList.add(parcelsAfterTransaction);
		
		
		return new GenericFeature(transactionFeatureType,
				String.valueOf(getObjectFeature().getPresentationId()),
				propertyList, GMLVersion.GML_31);
	}
	
	private GenericProperty generateParcelsProperty(ArrayPropertyType apt, boolean beforeState) {
		List<TypedObjectNode> parcelList = new ArrayList<TypedObjectNode>();
		
		if (beforeState) {
			for (ISpatialZone sz : getRequestedSpatialZones()) {
				if (sz instanceof IParcel) {
					IParcel parcel = (IParcel) sz;
					parcelList.add(new ParcelGMLProducer(getJurisdictionCode(), parcel).buildFeature());
				}
			}
		}
		else {
			for (ISpatialZone sz : getInCourseSpatialZones()) {
				if (sz instanceof IParcel) {
					IParcel parcel = (IParcel) sz;
					parcelList.add(new ParcelGMLProducer(getJurisdictionCode(), parcel).buildFeature());
				}
			}
		}
		
		return new GenericProperty(apt, new GenericXMLElementContent(null, null, parcelList));
	}

	private List<ISpatialZone> inCourseSpatialZones;
	public List<ISpatialZone> getInCourseSpatialZones() {
		if (inCourseSpatialZones == null) {
			ITransaction trx = getObjectFeature();
			inCourseSpatialZones = new ArrayList<ISpatialZone>();
			if (trx != null && !trx.isCompleted()) {
				for (ISpatialZone sz : ParcelDAO.loadParcelsAfterTransactionByPresentationId(trx.getPresentationId()))
					inCourseSpatialZones.add(sz);
			}
		}
		return inCourseSpatialZones;
	}

	private List<ISpatialZone> requestedSpatialZones;
	public List<ISpatialZone> getRequestedSpatialZones() {
		if (requestedSpatialZones == null) {
			ITransaction trx = getObjectFeature();
			requestedSpatialZones = new ArrayList<ISpatialZone>();
			if (trx != null)
				addSpatialZones(requestedSpatialZones, (HND_Transaction)trx, 0);
		}
		return requestedSpatialZones;
	}
	
	
	private void addSpatialZones(List<ISpatialZone> listToAdd, HND_Transaction transaction, int neighborLevel) {
		if (listToAdd == null || transaction == null) return;
		
		for (HND_SpatialZoneInTransaction szit : transaction.getSpatialZoneInTransactions())
			if (szit.getNeighborLevel() == neighborLevel)
				listToAdd.add(szit.getSpatialZone());
	}
}
